#include <stdio.h>
#include <ulog/ulog.h>
#include "iic_function.h"
#include "camera_config.h"
#include "drv_isp.h"
#include "soc.h"
#include "pin_name.h"
#include "bf2253_drv.h"
#include "drv_gpio.h"
#include "reg_deal.h"
#include "cli_api.h"

#define BF2253_MODULE "bf2253"

static i2c_dev_t i2c_bf2253_right;
static i2c_dev_t i2c_bf2253_left;

typedef enum 
{
    CFG_MODE_NONE = 0,		
    CFG_MODE_RGB_1080P_YUV,
    CFG_MODE_RGB_720P_YUV,
    CFG_MODE_RGB_640X360_RGB,
    CFG_MODE_IR_720P_YUV,
    CFG_MODE_IR_720P_RAW10,
    CFG_MODE_IR_640x360_RAW,
}SENSOR_CFG_MODE_E;

// 1280x720
const regval_list bf2253_1280x720_raw10[] = {
	{0xf2,0x01},
	{0xe1,0x06},
	{0xe2,0x06},  // 0x06
	{0xe3,0x02},  // 0x02 -> 0x0e
	{0xe4,0x40},

	//{0xcb, 0x40}, 
	//{0xcf, 0x38},
	
	{0xe5,0x67},
	{0xe6,0x02},
	{0xe8,0x84},
	{0x01,0x14},
	{0x03,0x98},
	{0x27,0x21},
	//{0x24, 0x00}, 
	{0x29,0x20},
	{0x59,0x10},
	{0x5a,0x10},   
	{0x5c,0x11},
	{0x5d,0x73},
	{0x6a,0x2f},
	{0x6b,0x0e},
	{0x6c,0x7e},
	{0x6f,0x10},
	{0x70,0x08},
	{0x71,0x05},
	{0x72,0x10},
	{0x73,0x08},
	{0x74,0x05},
	{0x75,0x06},
	{0x76,0x20},
	{0x77,0x03},
	{0x78,0x0e},
	{0x79,0x08},
    // //MIPI: 1LANE
    // {0x7d,0x1f},

    {0xca,0X50},  
    {0xcb,0x20},  
    {0xcc,0x00}, //h_start: {0xca[3:0],0xcc}, 
    {0xcd,0x00}, //h_end: {0xca[7:4],0xcd},
    {0xce,0x00}, //v_start: {0xcb[3:0],0xce},               
    {0xcf,0xd0}, //v_end: {0xcb[7:4], 0xcf},
	{0xe0,0x00},
};

const regval_list bf2253_1280x720_raw8[] = {
	{0xf2,0x01},
	{0xe1,0x00},
	{0xe2,0x08},  // 0x06
	{0xe3,0x06}, // 0x02 -> 0x0e
	{0xe4,0x40},

	//{0xcb, 0x40}, 
	//{0xcf, 0x38},
	
	{0xe5,0x67},
	{0xe6,0x02},
	{0xe8,0x84},
	{0x01,0x14},
	{0x03,0x98},
	{0x27,0x21},
	//{0x24, 0x00}, // add lanh
	{0x29,0x20},
	{0x59,0x10},
	{0x5a,0x10},
	{0x5c,0x11},
	{0x5d,0x73},
	{0x6a,0x2f}, //0x2f
	{0x6b,0x01},
	{0x6c,0x7e},
	{0x6f,0x10},
	{0x70,0x08},
	{0x71,0x05},
	{0x72,0x10},
	{0x73,0x08},
	{0x74,0x05},
	{0x75,0x06},
	{0x76,0x20},
	{0x77,0x03},
	{0x78,0x0e},
	{0x79,0x08},

	{0x7a,0x2a}, //0X2A :RAW8, 0X2B: RAW10
	{0x7e,0x00}, //0X2A :RAW8, 0X2B: RAW10

	// output window
    {0xca,0X50},  
    {0xcb,0x20},  
    {0xcc,0x00}, //h_start: {0xca[3:0],0xcc}, 
    {0xcd,0x00}, //h_end: {0xca[7:4],0xcd},
    {0xce,0x00}, //v_start: {0xcb[3:0],0xce},               
    {0xcf,0xd0}, //v_end: {0xcb[7:4], 0xcf},

	{0xe0,0x00}, //0x00
};

static const regval_list bf2253_1600x1200_raw10[] = {	
	{0xf2,0x01},// add lanh
	{0xe1,0x06},
	{0xe2,0x06},  // 0x06
	{0xe3,0x0f}, // 0x02 -> 0x0e
	{0xe4,0x40},

	//{0xcb, 0x40}, // add lanh
	//{0xcf, 0x38},
	
	{0xe5,0x67},
	{0xe6,0x02},
	{0xe8,0x84},
	{0x01,0x14},
	{0x03,0x98},
	{0x27,0x21},
	//{0x24, 0x00}, // add lanh
	{0x29,0x20},
	{0x59,0x10},
	{0x5a,0x10},
	{0x5c,0x11},
	{0x5d,0x73},
	{0x6a,0x2f},
	{0x6b,0x01},
	{0x6c,0x7e},
	{0x6f,0x10},
	{0x70,0x08},
	{0x71,0x05},
	{0x72,0x10},
	{0x73,0x08},
	{0x74,0x05},
	{0x75,0x06},
	{0x76,0x20},
	{0x77,0x03},
	{0x78,0x0e},
	{0x79,0x08},

	{0xe0,0x00},
	//{0x07,0xdc},
	//{0x08,0x0a},

	//{0xea, 0xff},
	//{0x7d,0x0e},
};


const  regval_list bf2253_sw_standby[] = {
	{0xe0 , 0x01},
};

const  regval_list bf2253_streaming[] = {
	{0xe0 , 0x00},
};


int bf2253_mode_config(bf2253_mode_t mode, uint8_t index)
{	
	int ret = 0;
	printf("%s >>>>  %d, mode %d \n",__func__, __LINE__, mode);

	if (BF2253_STANDBY == mode) {
		if(0 == index)
		{
			ret = iic_write_array_r8_d8(&i2c_bf2253_right, (struct regval_list *)bf2253_sw_standby, ARRAY_SIZE(bf2253_sw_standby));
		}
		else
		{
			ret = iic_write_array_r8_d8(&i2c_bf2253_left, (struct regval_list *)bf2253_sw_standby, ARRAY_SIZE(bf2253_sw_standby));
		}
		if (ret < 0) {
			return -1;
		}
	} 
	else {
		if(0 == index)
		{
			ret = iic_write_array_r8_d8(&i2c_bf2253_right, (struct regval_list *)bf2253_streaming, ARRAY_SIZE(bf2253_streaming));
		}
		else
		{
			ret = iic_write_array_r8_d8(&i2c_bf2253_left, (struct regval_list *)bf2253_streaming, ARRAY_SIZE(bf2253_streaming));
		}
		if (ret < 0) {
			return -1;
		}
	}

	return 0;
}

static int bf2253_check_id(i2c_dev_t *i2c)
{
    int ret = 0;
    uint8_t data = 0;

    ret = iic_read_r8_d8(i2c,  BF2253_REG_CHIPID_H, &data);
    printf("H %02x \n",data);
    if (ret < 0 || data != 0x22)
        return -1;
    ret = iic_read_r8_d8(i2c, BF2253_REG_CHIPID_L, &data);
    printf("L %02x \n",data);
   	if (ret < 0 || data != 0x53)
        return -1;
    return ret;
}

int bf2253_init(i2c_dev_t *i2c, uint32_t dev_addr)
{
   	memcpy(&i2c_bf2253_right, i2c, sizeof(i2c_dev_t));
    i2c_bf2253_right.config.dev_addr = dev_addr;
    //Check the id of camera
    int ret = bf2253_check_id(&i2c_bf2253_right);
    if (ret < 0) {
        printf("bf2253 check id fail\n");
        return ret;
    }

    img_cli_register();
    return ret;
}



static int bf2253_read_dark(i2c_dev_t *i2c)
{
    int ret = 0;
    uint8_t data = 0;

    ret = iic_read_r8_d8(i2c,  0x56, &data);
	printf("even row %02x \n",data);
    ret = iic_read_r8_d8(i2c, 0x57, &data);
	printf("odd row %02x \n",data);
	ret = iic_read_r8_d8(i2c, 0x58, &data);
	printf("even[4], odd[0] %02x \n",data);
    return ret;
}

int bf2253_hw_reset(void)
{
	//Config USI3_SD0 <=> GPIOB14  
#if 0	
    gpio_pin_handle = csi_gpio_pin_initialize(PB14, 0);
    csi_gpio_pin_config_mode(gpio_pin_handle, GPIO_MODE_PULLDOWN);
    csi_gpio_pin_config_direction(gpio_pin_handle, GPIO_DIRECTION_OUTPUT);
    csi_gpio_pin_write(gpio_pin_handle, 0);
	aos_msleep(5);
    csi_gpio_pin_write(gpio_pin_handle, 1);
#endif 	
    return 0;
}

int bf2253_right_init(i2c_dev_t *i2c, uint32_t dev_addr)
{
   	memcpy(&i2c_bf2253_right, i2c, sizeof(i2c_dev_t));
    i2c_bf2253_right.config.dev_addr = dev_addr;
    //Check the id of camera
   	int ret = bf2253_check_id(&i2c_bf2253_right);
    if (ret < 0) {
        printf("camera bf2253 check id failed !!! \n");
        return ret;
    }
    printf("dev_addr %d \n", dev_addr);
	printf("camera bf2253 check id success !!! \n");
    return ret;
}

int bf2253_left_init(i2c_dev_t *i2c, uint32_t dev_addr)
{
   	memcpy(&i2c_bf2253_left, i2c, sizeof(i2c_dev_t));
    i2c_bf2253_left.config.dev_addr = dev_addr;
    //Check the id of camera
   	int ret = bf2253_check_id(&i2c_bf2253_left);
    if (ret < 0) {
        printf("camera bf2253 left check id failed !!! \n");
        return ret;
    }
	printf("camera bf2253 left check id success !!! \n");
    return ret;
}


int32_t bf2253_config(imageFormat_t cfg)
{
	int32_t ret = 0;

	if( R_720P == cfg.res && RAW10 == cfg.format)
	{
		ret = iic_write_array_r8_d8(&i2c_bf2253_right, (struct regval_list *)bf2253_1280x720_raw10, ARRAY_SIZE(bf2253_1280x720_raw10));
		if (ret < 0) {
			return -1;
		}
		printf("bf2253_1280x720_raw10 success !!! \n");
	}
    else if( R_720P == cfg.res && RAW8 == cfg.format)
    {
        ret = iic_write_array_r8_d8(&i2c_bf2253_right, (struct regval_list *)bf2253_1280x720_raw8, ARRAY_SIZE(bf2253_1280x720_raw8));
		if (ret < 0) {
			return -1;
		}
		printf("bf2253_1280x720_raw8 success !!! \n");
    }
//	else if( R_1600x1200 == cfg.res && RAW10 == cfg.format)
//	{
//	    ret = iic_write_array_r8_d8(&i2c_bf2253_right, (struct regval_list *)bf2253_1600x1200_raw10, ARRAY_SIZE(bf2253_1600x1200_raw10));
//		if (ret < 0) {
//			return -1;
//		}
//	}
    //bf2253_read_dark(&i2c_bf2253_right);
	return ret;
}

#if 0
int switch_exposure_para(exposure_scene_t scene)
{
    int ret = 0;
	#if 0
    static regval_list expo_arg[] = { 
        {0x3501,0x2E},	//expo H		
        {0x3502,0x20},  //expo L
        {0x3509,0x20},  //gain
    };

    if (EXPOSURE_PARA_OUTDOOR == scene) {
        // expo 3ms
        expo_arg[0].data = 0x05;
        expo_arg[1].data = 0x86;
        expo_arg[2].data = 0x10;
    } else {
        // expo 4ms
        expo_arg[0].data = 0x07;
        expo_arg[1].data = 0x66;
        expo_arg[2].data = 0xa0;
    }

	LOGI(BF2253_MODULE, "cur_scene %s", scene == EXPOSURE_PARA_INDOOR ? "indoor " : "outdoor ");
    LOGI(BF2253_MODULE, "expo_h:%02x, expo_l: %02x, gain:%02x\n", expo_arg[0].data, expo_arg[1].data, expo_arg[2].data);
	printf( "cur_scene %s", scene == EXPOSURE_PARA_INDOOR ? "indoor " : "outdoor ");
    printf( "expo_h:%02x, expo_l: %02x, gain: %02x\n", expo_arg[0].data, expo_arg[1].data, expo_arg[2].data);

    ret = iic_write_array(&i2c_bf2253, (struct regval_list *)expo_arg, ARRAY_SIZE(expo_arg));
    if(ret != 0) {
        LOGI(BF2253_MODULE, " 9282 expo config error:%d \n", ret);
    }
	#endif
    return ret; 
}


int set_spk_exposure_para(exposure_scene_t scene)
{
    int ret = 0;
	#if 0
    static regval_list expo_arg[] = { 
        {0x3501,0},	//expo H		
        {0x3502,0},  //expo L
        {0x3509,0},  //gain
    };

    if (EXPOSURE_PARA_OUTDOOR == scene) {
        // expo 2ms
        expo_arg[0].data = 0x03;
        expo_arg[1].data = 0xb6;
        expo_arg[2].data = 0x10;

    } else {
        // expo 2ms
        expo_arg[0].data = 0x03;
        expo_arg[1].data = 0xb6;
        expo_arg[2].data = 0x20;
    }

    LOGI(BF2253_MODULE, "expo_h:%02x, expo_l: %02x, gain:%02x\n", expo_arg[0].data, expo_arg[1].data, expo_arg[2].data);

    ret = iic_write_array(&i2c_bf2253, (struct regval_list *)expo_arg, ARRAY_SIZE(expo_arg));
    if(ret != 0) {
        LOGE(BF2253_MODULE, " 9282 expo config error:%d \n", ret);
    }
	#endif
    return ret; 
}


int bf2253_set_exposure_para(regval_list *expo_arg, uint32_t size)
{
    int ret = 0;

    ret = iic_write_array(&i2c_bf2253, (struct regval_list *)expo_arg, size);
    if(ret != 0) {
        LOGI(BF2253_MODULE, " 9282 expo config error:%d \n", ret);
    }
	
    return ret; 
}

int bf2253_get_exposure_para(regval_list *expo_arg, uint32_t size)
{
    int ret = 0;

    ret = iic_read_array(&i2c_bf2253, (struct regval_list *)expo_arg, size);
    if(ret != 0) {
        LOGI(BF2253_MODULE, " BF2253 expo config error:%d \n", ret);
    }
	
    return ret; 
}

int set_bf2253_reglist(regval_list reglist[], uint32_t reglist_len)
{
    int ret = 0;

    ret = iic_write_array(&i2c_bf2253, (struct regval_list *)reglist, reglist_len);
    if(ret != 0) {
        LOGE(BF2253_MODULE, " 9282 expo config error:%d \n", ret);
    }
    return ret; 
}
#endif


regval_list bf2253_config_reg[] = {
	{0x00 , 0x00},
};

int bf2253_write(uint8_t reg, uint8_t value){

    int ret = 0;
    bf2253_config_reg[0].addr = reg;
    bf2253_config_reg[0].data = value;
    ret = iic_write_array_r8_d8(&i2c_bf2253_right, (struct regval_list *)bf2253_config_reg, ARRAY_SIZE(bf2253_config_reg));

}

int bf2253_read(uint8_t reg){

    int ret = 0;
    uint8_t data[2] = {0};

    ret = iic_read_r8_d8(&i2c_bf2253_right,  reg, &data);

    printf("read reg 0x%02x value 0x%x \n", reg,data[0]);
}


int bf2253_write2(i2c_dev_t *i2c, uint32_t dev_addr, uint8_t reg, uint8_t value){

    int ret = 0;
    memcpy(&i2c_bf2253_right, i2c, sizeof(i2c_dev_t));
    i2c_bf2253_right.config.dev_addr = dev_addr;
    
    ret = iic_write_r8_d8(&i2c_bf2253_right, reg, value);

}

int bf2253_read2(i2c_dev_t *i2c, uint32_t dev_addr, uint8_t reg){

    int ret = 0;
    uint8_t data[2] = {0};

    memcpy(&i2c_bf2253_right, i2c, sizeof(i2c_dev_t));
    i2c_bf2253_right.config.dev_addr = dev_addr;

    ret = iic_read_r8_d8(&i2c_bf2253_right,  reg, &data);

    //printf("read reg 0x%02x value 0x%x \n", reg,data[0]);
}


void sensor_command(char *outbuf, int len, int argc, char **argv)
{
    uint8_t reg = 0;
    uint8_t value = 0;

    if (argc == 1) {
        printf("wrong argv numer.\n");
        return;
    }
    if (!strcmp(argv[1], "set")) {
        reg = strtoul(argv[2], NULL, 16);
        value = strtoul(argv[3], NULL, 16);
        printf("set reg 0x%x, value 0x%x ", reg, value);
        bf2253_write(reg, value);
        
    } 
    else if (!strcmp(argv[1], "get")) {
        
            reg = strtoul(argv[2], NULL, 16);
            
            printf("get reg 0x%x \n", reg);
            bf2253_read(reg);
        }
    else {
        cli_printf("param invalid!\n");
        return;
    }

    return;
}




static const struct cli_command_st img_cli_cmd[] = 
{
    [0] =
    {
        .name            = "sensor",
        .help            = "sensor set/get register",
        .function        = sensor_command
    },

};


int img_cli_register(void) 
{
    int ret = 0;

    ret = cli_register_commands(img_cli_cmd, sizeof(img_cli_cmd)/sizeof(struct cli_command_st));
    if (ret != 0) {
        return ret;
    }

    return 0;
}



